package editorsvg.editor.documento;

import editorsvg.editor.comandos.GestorComandos;
import editorsvg.editor.formas.Pintable;
import editorsvg.geometria.MiDimension2D;
import editorsvg.gui.generico.Actualizable;
import editorsvg.propiedades.DefinicionPropiedades;
import editorsvg.propiedades.GrupoPropiedades;
import editorsvg.propiedades.PropiedadTexto;
import editorsvg.propiedades.PropiedadTransformacion;
import editorsvg.utilidades.Angulo;
import java.awt.Shape;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

/**
 *
 * @author Jorge Berjano
 */
public abstract class ElementoGrafico implements Pintable, Actualizable, Cloneable {

    private String nombreTag;
    private String id;
    private String clase;
    private Transformacion transformacion = new Transformacion();
    private boolean bloqueado;
    
    protected DefinicionPropiedades propiedades;
    private GrupoPropiedades propiedadesIdentificacion;
    private GrupoPropiedades propiedadesTransformacion;

    public ElementoGrafico() {
        propiedades = new DefinicionPropiedades();

        propiedadesIdentificacion = new GrupoPropiedades("Identificacion");
        propiedadesIdentificacion.agregarPropiedad(new PropiedadTexto(this, "id"));
        propiedadesIdentificacion.agregarPropiedad(new PropiedadTexto(this, "clase"));
        agregarPropiedades(propiedadesIdentificacion);

        propiedadesTransformacion = new GrupoPropiedades("Transformacion");
        propiedadesTransformacion.agregarPropiedad(new PropiedadTransformacion(this, "transformacion", "transform"));
        agregarPropiedades(propiedadesTransformacion);
    }

    public void setGestorComandos(GestorComandos gestorComandos) {
        propiedades.setGestorComandos(gestorComandos);
    }

    protected void agregarPropiedades(GrupoPropiedades grupo) {
        propiedades.agregar(grupo);
    }

    public DefinicionPropiedades getPropiedades() {
        return propiedades;
    }

    @Override
    public String toString() {
        return "<" + nombreTag + (id != null && id.length() > 0 ? " id=\"" + id + "\"" : "") + ">";
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        ElementoGrafico clon = (ElementoGrafico) super.clone();
        clon.transformacion = (Transformacion) transformacion.clone();
        
        clon.propiedades = new DefinicionPropiedades();
        
        clon.propiedadesIdentificacion = (GrupoPropiedades) propiedadesIdentificacion.clone();    
        clon.propiedadesIdentificacion.asignarObjeto(clon);
        clon.agregarPropiedades(clon.propiedadesIdentificacion);
        
        clon.propiedadesTransformacion = (GrupoPropiedades) propiedadesTransformacion.clone();
        clon.propiedadesTransformacion.asignarObjeto(clon);
        clon.agregarPropiedades(clon.propiedadesTransformacion);
        
        return clon;
    }

    public boolean contiene(Point2D posicion) {
        Shape contorno = getContorno();
        return contorno == null ? false : contorno.contains(posicion);
    }

    public boolean contiene(Point2D posicion, double tolerancia) {
        Shape contorno = getContorno();
        Rectangle2D rectangulo = new Rectangle2D.Double(
                posicion.getX() - tolerancia / 2,
                posicion.getY() - tolerancia / 2,
                tolerancia, tolerancia);
        return contorno == null ? false : contorno.contains(rectangulo) || contorno.intersects(rectangulo);
    }

    public Transformacion getTransformacion() {
        return transformacion;
    }

    public void setTransformacion(Transformacion transformacion) {
        this.transformacion = transformacion;
    }

    public void transformar(Transformacion transformacion) {
        getTransformacion().combinar(transformacion);
    }

    public void desplazar(double dx, double dy) {
        getTransformacion().desplazar(dx, dy);
    }

    public void escalar(Rectangle2D encuadreInicial, Rectangle2D encuadreFinal) {
        getTransformacion().escalar(encuadreInicial, encuadreFinal);
    }

    public void rotar(Angulo anguloRotacion, double x, double y) {
        getTransformacion().rotar(anguloRotacion, x, y);
    }

    public boolean estaBloqueado() {
        return bloqueado;
    }

    public abstract Shape getContorno();

    public Rectangle2D getEncuadre() {
        return getContorno().getBounds2D();
    }

    public Dimension2D getTamaño() {
        return new MiDimension2D.Double(getEncuadre().getWidth(), getEncuadre().getHeight());
    }

    public Point2D getCentro() {
        return new Point2D.Double(getEncuadre().getX(), getEncuadre().getY());
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClase() {
        return clase;
    }

    public void setClase(String clase) {
        this.clase = clase;
    }

    /**
     * Recorre el elemento permitiendo al visitante visitar este elemento y
     * todos los que contenga.
     * @param visitante El visitante.
     * @return False si se desea interrumpir la visita.
     */
    public boolean recorrer(Visitante visitante) {
        return visitante.visitar(this);
    }

    public String getNombreTag() {
        return nombreTag;
    }

    public void setNombreTag(String nombreElemento) {
        this.nombreTag = nombreElemento;
    }

//    public void setObservadorPropiedades(ObservadorPropiedad observador) {
//        propiedades.agregarObservador(observador);
//
//    }
}
